package com.xiaoying.server.publish.servlet;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;



import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Service;

import com.xiaoying.server.publish.Handler;
import com.xiaoying.server.publish.entity.FileInfo;
import com.xiaoying.server.publish.entity.UploadResult;
import com.xiaoying.server.publish.impl.ExceptionHandler;
import com.xiaoying.server.publish.impl.FetchRequest;
import com.xiaoying.server.publish.impl.ResponseHandler;
import com.xiaoying.server.publish.impl.BackupUploadInfoHandler;


@Service("dispatcher")
public class Dispatcher {
	private static String baseDir = System.getProperty("user.dir")+"\\file";
    private static Log log = LogFactory.getFactory().getInstance(Dispatcher.class);

    // 上传文件请求队列
    private BlockingQueue<FileInfo> reqQueue;
    // 上传结果结果处理队列
    private BlockingQueue<UploadResult> resQueue;
    
    /**
     * 已经上传的文件，需要del Redis中信息
     * 因为Redis多线程调用客户端经常抛出Read timed out异常
     * 每个线程获取一个新的客户端，资源消耗严重，多个客户端炒作也容易出现Redis连接堵塞异常
     * <br> redisBackupKeyQueue作为移除备份信息线程和ResponseHandler线程中间通知队列
     * redis 移除备份信息速度是ms级别,但是如果2个线程同时来del key，抛Read timed out异常
     */
    private BlockingQueue<String> redisBackupQueue;
    
    // 上传文件处理动作
    private Handler requestHandler;
    // 上传结果处理动作
    private ResponseHandler responseHandler;
    // 异常退出处理动作
    private Handler exceptionHandler;
    // 备份信息移除处理动作
    private BackupUploadInfoHandler backupUploadInfoHandler;
    
    // 上传文件队列最大容量
    private int maxReqCache;
    // 上传结果队列最大容量
    private int maxResCache;
    // Redis备份队列的最大容量
    private int maxBackupCache;
    
    
    private Dispatcher() {
    	
    }
    
    private static class DispatcherHolder {
        static final Dispatcher UNIQUEINSTANCE = new Dispatcher();
    }
    
    public static Dispatcher getInstance() {
        return DispatcherHolder.UNIQUEINSTANCE;
    }
    
    public void init() throws Exception {
    	reqQueue = new LinkedBlockingQueue<FileInfo>(maxReqCache);
        resQueue = new LinkedBlockingQueue<UploadResult>(maxResCache);
        redisBackupQueue = new LinkedBlockingQueue<String>();
        requestHandler.init();        
        responseHandler.init();
        responseHandler.setBackupQueue(redisBackupQueue);
        exceptionHandler = new ExceptionHandler();
        backupUploadInfoHandler = new BackupUploadInfoHandler();
        ShutdownHook();
    }
    
    public void startup() throws InterruptedException {
    	log.info("XiaoYing文件上传服务器启动中...");
        exceptionHandler.handle(reqQueue , resQueue);
        Thread.sleep(2000L);	//wait 2s
        // 异常处理开始后10L开始主线程
		new FetchRequest(reqQueue , resQueue);
        requestHandler.handle(reqQueue, resQueue);
        responseHandler.handle(reqQueue, resQueue);
        backupUploadInfoHandler.handler(redisBackupQueue);
    }
    
    public void ShutdownHook() throws Exception {
        Runtime.getRuntime().addShutdownHook(new Thread() {
            public void run() {
                log.info("XiaoYing文件上传服务器即将停止，检查队列中是否还有待处理数据。");
                while (!(reqQueue.isEmpty() && resQueue.isEmpty())) {
                    try {
                        wait(1000); //等待数据处理
                    } catch (InterruptedException e) {
                       log.error(e);
                    }
                }
                log.info("队列中数据已经处理完毕，上传文件服务器停止。");
            }
        });
    }
    
    

	public ResponseHandler getResponseHandler() {
		return responseHandler;
	}

	public void setResponseHandler(ResponseHandler responseHandler) {
		this.responseHandler = responseHandler;
	}

	public Handler getExceptionHandler() {
		return exceptionHandler;
	}

	public void setExceptionHandler(Handler exceptionHandler) {
		this.exceptionHandler = exceptionHandler;
	}

	public Handler getRequestHandler() {
		return requestHandler;
	}

	public void setRequestHandler(Handler requestHandler) {
		this.requestHandler = requestHandler;
	}

	public int getMaxReqCache() {
		return maxReqCache;
	}

	public void setMaxReqCache(int maxReqCache) {
		this.maxReqCache = maxReqCache;
	}

	public int getMaxResCache() {
		return maxResCache;
	}

	public void setMaxResCache(int maxResCache) {
		this.maxResCache = maxResCache;
	}

	public int getMaxBackupCache() {
		return maxBackupCache;
	}

	public void setMaxBackupCache(int maxBackupCache) {
		this.maxBackupCache = maxBackupCache;
	}
	
}
